Attribute VB_Name = "modMiniX2"
Option Explicit

Public Enum MX2TubeTypeEnum
    mx2tubetype50kV4W
    mx2tubetype50kV10W
    mx2tubetype70kV10W
End Enum

Public Type Stat_MNX
    RAW(64) As Byte
    SN As Long
    FW As Byte
    Build As Byte
    PWR_IN As Single
    PWR_XRAY As Single
    HV_MON As Single
    HV_MON_RAW As Single
    I_MON As Single
    I_MON_RAW As Single
    LAMP_I As Single
    Temp As Single
    HV_EN As Boolean
    PWR_XRAY_FLAG As Boolean
    INTERLOCK_STATE As Byte
    LAST_FAULT As Byte
    SPEAKER_EN As Boolean
    DISABLE_FAULT_CHECKS As Boolean
    DISABLE_LIMIT_CHECKS As Boolean
    WARMUP_STEP As Byte
    WARMUP_TIME As Integer
    RUNTIME As Long
    ULTRAMINI_PRESENT As Boolean
    HVScale As Single
    IScale As Single
End Type

Public STATUS_MNX As Stat_MNX   ' 64 byte status packet for Mini-X
Public varMiniX2_Faults As Variant
Public PIN_buffer(520) As Byte
Public Fault(16) As String
Public isMiniX2 As Boolean
Public bHaveTubeType As Boolean
Public mx2ttTubeType As MX2TubeTypeEnum

Public strMX2CfgIn As String
Public bMX2CfgReady As Boolean

Public Function MX2TubeTypeEnumToString(mx2ttTubeType As MX2TubeTypeEnum) As String
    MX2TubeTypeEnumToString = "Tube Type Unknown"
    Select Case mx2ttTubeType
        Case mx2tubetype50kV4W
            MX2TubeTypeEnumToString = "50kV4W"
        Case mx2tubetype50kV10W
            MX2TubeTypeEnumToString = "50kV10W"
        Case mx2tubetype70kV10W
            MX2TubeTypeEnumToString = "70kV10W"
    End Select
End Function


Public Sub Process_MNX_Status(ByRef STATUS_MNX As Stat_MNX)
' This is called by Form1.ParsePacket
    Dim S As Single
    
    isMiniX2 = True
    
    STATUS_MNX.FW = PIN.Data(4)
    STATUS_MNX.Build = PIN.Data(5) And 15
    STATUS_MNX.SN = CLng(PIN.Data(3) And &H7F) * (2 ^ 24) + CLng(PIN.Data(2)) * (2 ^ 16) + CLng(PIN.Data(1)) * 256 + CLng(PIN.Data(0))
    
    
    S = CSng((PIN.Data(15) And 15)) * 256 + CSng(PIN.Data(14))
    STATUS_MNX.PWR_IN = S / 1000 * 3.26
    
    S = CSng((PIN.Data(13) And 15)) * 256 + CSng(PIN.Data(12))
    STATUS_MNX.PWR_XRAY = S / 1000 * 3.26

    S = CSng((PIN.Data(11) And 15)) * 256 + CSng(PIN.Data(10))
    STATUS_MNX.LAMP_I = S / 1000 * 12.44    ' in mA
    
    S = CSng((PIN.Data(9) And 15)) * 256 + CSng(PIN.Data(8))
    STATUS_MNX.I_MON_RAW = S / 1000                                 ' monitor, in V
    'STATUS_MNX.I_MON = STATUS_MNX.I_MON_RAW * Val(Form8.txtIScale.Text)    ' in uA

    S = CSng((PIN.Data(7) And 15)) * 256 + CSng(PIN.Data(6))
    STATUS_MNX.HV_MON_RAW = S / 1000                                 ' monitor, in V
    'STATUS_MNX.HV_MON = STATUS_MNX.HV_MON_RAW * Val(Form8.txtHVScale.Text)    ' in kV

    STATUS_MNX.HV_EN = (PIN.Data(16) And &H80)          ' D7
    STATUS_MNX.PWR_XRAY_FLAG = (PIN.Data(16) And &H20)  ' D5
    STATUS_MNX.INTERLOCK_STATE = (PIN.Data(16) And 15)  ' D3-D0
    
    S = CSng(PIN.Data(17))
    If S > 127 Then ' 8-bit signed
        S = S - 256
    End If
    STATUS_MNX.Temp = S
    
    STATUS_MNX.LAST_FAULT = (PIN.Data(18) And 15)                ' D3-D0
    STATUS_MNX.SPEAKER_EN = (PIN.Data(18) And 128)               ' D7
    STATUS_MNX.DISABLE_FAULT_CHECKS = (PIN.Data(18) And 64)      ' D6
    STATUS_MNX.DISABLE_LIMIT_CHECKS = (PIN.Data(18) And 32)      ' D5
    STATUS_MNX.ULTRAMINI_PRESENT = (PIN.Data(18) And 16)         ' D4

    STATUS_MNX.WARMUP_STEP = PIN.Data(19)
    STATUS_MNX.WARMUP_TIME = PIN.Data(20) + (PIN.Data(21) And &H7F) * 256   ' avoid overflow
    
    'STATUS_MNX.RUNTIME = CLng(PIN.Data(22) And &H7F) * (2 ^ 24) + CLng(PIN.Data(23)) * (2 ^ 16) + CLng(PIN.Data(24)) * 256 + CLng(PIN.Data(25))
    STATUS_MNX.RUNTIME = CLng(PIN.Data(25) And &H7F) * (2 ^ 24) + CLng(PIN.Data(24)) * (2 ^ 16) + CLng(PIN.Data(23)) * 256 + CLng(PIN.Data(22))
    
    Dim HVScale As Single
    HVScale = CSng((CLng(PIN.Data(26)) * 256& + CLng(PIN.Data(27))) / 256&)
    STATUS_MNX.HVScale = Format(HVScale, "##0.000")
    STATUS_MNX.HV_MON = STATUS_MNX.HV_MON_RAW * STATUS_MNX.HVScale    ' in kV
    
    Dim IScale As Single
    IScale = CSng((CLng(PIN.Data(28)) * 256& + CLng(PIN.Data(29))) / 256&)
    STATUS_MNX.IScale = Format(IScale, "##0.000")
    STATUS_MNX.I_MON = STATUS_MNX.I_MON_RAW * STATUS_MNX.IScale    ' in uA


' Tube P/N, S/N and Description are in tube table
' Mini-X S/N?

End Sub

Public Function Process_MNX_Fault_Record(PIN As Packet_In) As String
    Dim idxData As Long
    Dim FaultTime As Date
    Dim Timetag_lag As Long
    Dim H As Long, m As Long, S As Long
    Dim strFault As String
    
    For idxData = 0 To PIN.LEN - 1
        PIN_buffer(idxData) = PIN.Data(idxData) ' copy the fault record packet
    Next idxData
    
    strFault = "======= Fault Record ===========" + vbCrLf
    strFault = strFault + "======= Unit Info ===========" + vbCrLf
    strFault = strFault + "Fault Record read at: " + Format(Now, "MM/DD/YYYY hh:mm:ss AM/PM") + vbCrLf
    
    If PIN.Data(1) < 128 Then
        FaultTime = DateSerial(2000 + PIN.Data(4), PIN.Data(2), PIN.Data(3))   ' date
        FaultTime = FaultTime + TimeSerial(PIN.Data(5), PIN.Data(6), PIN.Data(7))
        Timetag_lag = CLng(PIN.Data(8) And &H7F) * (2 ^ 24) + CLng(PIN.Data(9)) * (2 ^ 16) + CLng(PIN.Data(10)) * 256 + CLng(PIN.Data(11))
        FaultTime = DateAdd("s", Timetag_lag, FaultTime)
        ' Get runtime from status instead
        'Runtime = CLng(PIN.Data(11) And &H7F) * (2 ^ 24) + CLng(PIN.Data(12)) * (2 ^ 16) + CLng(PIN.Data(13)) * 256 + CLng(PIN.Data(14))
        strFault = strFault + "Fault occurred at: " + Format(FaultTime, "MM/DD/YYYY hh:mm:ss AM/PM") + vbCrLf
        
    Else    ' unintialized timestamp
    
    End If
    
    ' Copy the status from buffer back into PIN, where Process_MNX_Status expects it
    For idxData = 0 To 63
        PIN.Data(idxData) = PIN_buffer(idxData + 18)
    Next idxData
    Process_MNX_Status STATUS_MNX
    strFault = strFault + "======= Mini-X2 Status ===========" + vbCrLf
    
    strFault = strFault + "Mini-X2 Serial Number: " + Format(STATUS_MNX.SN, "0000") + vbCrLf
    strFault = strFault + "Firmware Version: " + Format(STATUS_MNX.FW \ 16, "#0.") + Format(STATUS_MNX.FW And 15, "00.") + Format(STATUS_MNX.Build, "00") + vbCrLf
    strFault = strFault + "Supply Voltage (Mini-X): " + Format(STATUS_MNX.PWR_IN, "#0.00V") + vbCrLf
    strFault = strFault + "Supply Voltage (to tube): " + Format(STATUS_MNX.PWR_XRAY, "#0.00V") + vbCrLf
    strFault = strFault + "Tube HV Mon: " + Format(STATUS_MNX.HV_MON, "#0.00kV") + vbCrLf
    strFault = strFault + "Tube HV Mon (raw): " + Format(STATUS_MNX.HV_MON_RAW, "0.000V") + vbCrLf
    strFault = strFault + "Tube Current Mon: " + Format(STATUS_MNX.I_MON, "##0.00uA") + vbCrLf
    strFault = strFault + "Tube Current Mon (raw): " + Format(STATUS_MNX.I_MON_RAW, "0.000V") + vbCrLf
    strFault = strFault + "Interlock Current: " + Format(STATUS_MNX.LAMP_I, "#0.00mA") + vbCrLf
    strFault = strFault + "Board Temp: " + Format(STATUS_MNX.Temp, "##0°C") + vbCrLf
    If STATUS_MNX.HV_EN Then
        strFault = strFault + "HV_EN State: Enabled" + vbCrLf
    Else
        strFault = strFault + "HV_EN State: Disabled" + vbCrLf
    End If
    strFault = strFault + "Current Fault: " + Fault(STATUS_MNX.INTERLOCK_STATE) + vbCrLf
    If STATUS_MNX.LAST_FAULT > 0 Then
        strFault = strFault + "Previous Fault: " + Fault(STATUS_MNX.LAST_FAULT) + vbCrLf
    Else
        strFault = strFault + "Previous Fault: none" + vbCrLf
    End If
    
    H = STATUS_MNX.RUNTIME \ 3600
    m = (STATUS_MNX.RUNTIME - H * 3600) \ 60
    S = STATUS_MNX.RUNTIME - H * 3600 - m * 60
    strFault = strFault + "Tube Runtime: " + Format(H, "###0h") + " " + Format(m, "00m") + " " + Format(S, "00s") + vbCrLf
    
    If STATUS_MNX.DISABLE_LIMIT_CHECKS Then
        strFault = strFault + "Command Limit Checks: Disabled" + vbCrLf
    Else
        strFault = strFault + "Command Limit Checks: Enabled" + vbCrLf
    End If
    
    If STATUS_MNX.DISABLE_FAULT_CHECKS Then
        strFault = strFault + "Fault Checks: Disabled" + vbCrLf
    Else
        strFault = strFault + "Fault Checks: Enabled" + vbCrLf
    End If
    
    If STATUS_MNX.SPEAKER_EN Then
        strFault = strFault + "Speaker: Enabled" + vbCrLf
    Else
        strFault = strFault + "Speaker: Disabled" + vbCrLf
    End If
    
    If STATUS_MNX.WARMUP_STEP > 127 Then    ' MSB is set if warmup is running
        strFault = strFault + "Warmup Step: " + Format(STATUS_MNX.WARMUP_STEP And 15, "#0") + vbCrLf
        strFault = strFault + "Warmup step time: " + Format(STATUS_MNX.WARMUP_TIME, "##0s") + vbCrLf
    Else
        strFault = strFault + "Warmup: not running" + vbCrLf
    End If
    
    strFault = strFault + "======= Tube Table ===========" + vbCrLf
    strFault = strFault + "Tube Part Number: "
    For idxData = 0 To 19
        If PIN_buffer(idxData + 82) > 0 Then
            strFault = strFault + Chr(PIN_buffer(idxData + 82))
        Else
            Exit For
        End If
    Next idxData
    strFault = strFault + vbCrLf

    strFault = strFault + "Tube Serial Number: "
    For idxData = 0 To 11
        If PIN_buffer(idxData + 82 + 20) > 0 Then
            strFault = strFault + Chr(PIN_buffer(idxData + 82 + 20))
        Else
            Exit For
        End If
    Next idxData
    strFault = strFault + vbCrLf

    strFault = strFault + "Tube Description: "
    For idxData = 0 To 31
        If PIN_buffer(idxData + 82 + 62) > 0 Then
            strFault = strFault + Chr(PIN_buffer(idxData + 82 + 62))
        Else
            Exit For
        End If
    Next idxData
    strFault = strFault + vbCrLf

    strFault = strFault + "HVmin: " + Format(PIN_buffer(82 + 32), "##0kV") + vbCrLf
    strFault = strFault + "HVmax: " + Format(PIN_buffer(82 + 33), "##0kV") + vbCrLf
    strFault = strFault + "Imin: " + Format(PIN_buffer(82 + 34), "##0uA") + vbCrLf
    strFault = strFault + "Imax: " + Format(CInt(PIN_buffer(82 + 35) And 127) * 256 + PIN_buffer(82 + 36), "##0uA") + vbCrLf
    strFault = strFault + "Pmax anode: " + Format(PIN_buffer(82 + 37) / 4, "#0.00W") + vbCrLf
    strFault = strFault + "HVscale: " + Format((CInt(PIN_buffer(82 + 44) And 127) * 256 + PIN_buffer(82 + 45)) / 256, "##0.00kV/V") + vbCrLf
    strFault = strFault + "Iscale: " + Format((CInt(PIN_buffer(82 + 46) And 127) * 256 + PIN_buffer(82 + 47)) / 256, "##0.00uA/V") + vbCrLf

    strFault = strFault + "======= Interlock Table ===========" + vbCrLf
    strFault = strFault + "Interlock Voltage: " + Format(PIN_buffer(82 + 48) * 0.02, "0.00V") + vbCrLf
    strFault = strFault + "Interlock Current Min: " + Format((CInt(PIN_buffer(82 + 49) And 127) * 256 + PIN_buffer(82 + 50)) * 0.01244, "#0.00mA") + vbCrLf
    strFault = strFault + "Interlock Current Max: " + Format((CInt(PIN_buffer(82 + 51) And 127) * 256 + PIN_buffer(82 + 52)) * 0.01244, "#0.00mA") + vbCrLf
    strFault = strFault + "Tube Supply Min: " + Format(PIN_buffer(82 + 53) / 16, "#0.00V") + vbCrLf
    strFault = strFault + "Tube Supply Max: " + Format(PIN_buffer(82 + 54) / 16, "#0.00V") + vbCrLf

    strFault = strFault + "======= Warmup Table ===========" + vbCrLf
    
    Dim DailyWarmupTotalTime As Long
    Dim MonthlyWarmupTotalTime As Long
    Dim WarmupTime As Long
    Dim lWup As Long

    DailyWarmupTotalTime = 0
    MonthlyWarmupTotalTime = 0
    For idxData = 0 To 11
        WarmupTime = CInt(PIN_buffer(82 + 96 + idxData * 4) And 127) * 256 + PIN_buffer(82 + 97 + idxData * 4)
        If idxData < 6 Then
            strFault = strFault + "Daily Warmup Step #" + Format(idxData + 1, "#0") + ": "
            DailyWarmupTotalTime = DailyWarmupTotalTime + WarmupTime
        Else
            strFault = strFault + "Monthly Warmup Step #" + Format(idxData - 5, "#0") + ": "
            MonthlyWarmupTotalTime = MonthlyWarmupTotalTime + WarmupTime
        End If
        strFault = strFault + Format(PIN_buffer(82 + 94 + idxData * 4), "##0kV") + ", "
        strFault = strFault + Format(PIN_buffer(82 + 95 + idxData * 4), "##0uA") + ", "
        strFault = strFault + Format(WarmupTime, "###0") + "sec" + vbCrLf
        If (idxData = 5) Then
            lWup = CLng(DailyWarmupTotalTime)
            'MsgBox lWup
            strFault = strFault + "Daily Warmup Total time = " + Format(lWup \ 60, "#0m ") + Format(lWup Mod 60, "00s") + vbCrLf
        ElseIf (idxData = 11) Then
            lWup = CLng(MonthlyWarmupTotalTime)
            'MsgBox lWup
            strFault = strFault + "Monthly Warmup Total time = " + Format(lWup \ 60, "#0m ") + Format(lWup Mod 60, "00s") + vbCrLf
        End If
    Next idxData
    
    strFault = strFault + "======= Additional Fault Info ===========" + vbCrLf
    strFault = strFault + "Tube HV Setpoint: " + Format((CInt(PIN_buffer(226) And 127) * 256 + PIN_buffer(227)) / 256, "##0.00kV") + vbCrLf
    strFault = strFault + "Tube Current Setpoint: " + Format((CInt(PIN_buffer(228) And 127) * 256 + PIN_buffer(229)) / 256, "##0.00uA") + vbCrLf

    
    Process_MNX_Fault_Record = strFault
End Function

Public Sub CreateMiniX2FaultTable()
    Dim idxFault As Long
    varMiniX2_Faults = Array( _
    "Interlock: CLOSED", _
    "Interlock: OPEN", _
    "Interlock: SHORTED", _
    "Supply: VIN UV", _
    "Supply: VIN OV", _
    "Tube: HVMON LOW", _
    "Tube: HVMON HIGH", _
    "Tube: IMON LOW", _
    "Tube: IMON HIGH", _
    "USB: Disconnected", _
    "USB: Stopped Talking", _
    "Warmup: Done", _
    "TBD", "TBD", "TBD", "TBD")
    For idxFault = 0 To 15
        Fault(idxFault) = varMiniX2_Faults(idxFault)
    Next
End Sub

Public Function MiniX2_StatusToString(STATUS_MNX As Stat_MNX) As String
    Dim strStatus As String
    Dim H As Long, m As Long, S As Long
    On Error GoTo MiniX2_StatusToStringErr
    MiniX2_StatusToString = ""
    If (STATUS_MNX.SN = 0) Then Exit Function
    strStatus = ""
    strStatus = strStatus + "======= Mini-X2 Status ===============" + vbCrLf
    strStatus = strStatus + "Mini-X2 Serial Number: " + Format(STATUS_MNX.SN, "0000") + vbCrLf
    strStatus = strStatus + "Firmware Version: " + Format(STATUS_MNX.FW \ 16, "#0.") + Format(STATUS_MNX.FW And 15, "00.") + Format(STATUS_MNX.Build, "00") + vbCrLf
    strStatus = strStatus + "Supply Voltage (Mini-X): " + Format(STATUS_MNX.PWR_IN, "#0.00V") + vbCrLf
    strStatus = strStatus + "Supply Voltage (to tube): " + Format(STATUS_MNX.PWR_XRAY, "#0.00V") + vbCrLf
    strStatus = strStatus + "Tube HV Mon: " + Format(STATUS_MNX.HV_MON, "#0.00kV") + vbCrLf
    strStatus = strStatus + "Tube HV Mon (raw): " + Format(STATUS_MNX.HV_MON_RAW, "0.000V") + vbCrLf
    strStatus = strStatus + "Tube Current Mon: " + Format(STATUS_MNX.I_MON, "##0.00uA") + vbCrLf
    strStatus = strStatus + "Tube Current Mon (raw): " + Format(STATUS_MNX.I_MON_RAW, "0.000V") + vbCrLf
    strStatus = strStatus + "Interlock Current: " + Format(STATUS_MNX.LAMP_I, "#0.00mA") + vbCrLf
    strStatus = strStatus + "Board Temp: " + Format(STATUS_MNX.Temp, "##0°C") + vbCrLf
    If STATUS_MNX.HV_EN Then
        strStatus = strStatus + "HV_EN State: Enabled" + vbCrLf
    Else
        strStatus = strStatus + "HV_EN State: Disabled" + vbCrLf
    End If
    strStatus = strStatus + "Current Fault: " + Fault(STATUS_MNX.INTERLOCK_STATE) + vbCrLf
    If STATUS_MNX.LAST_FAULT > 0 Then
        strStatus = strStatus + "Previous Fault: " + Fault(STATUS_MNX.LAST_FAULT) + vbCrLf
    Else
        strStatus = strStatus + "Previous Fault: none" + vbCrLf
    End If
    
    H = STATUS_MNX.RUNTIME \ 3600
    m = (STATUS_MNX.RUNTIME - H * 3600) \ 60
    S = STATUS_MNX.RUNTIME - H * 3600 - m * 60
    strStatus = strStatus + "Tube Runtime: " + Format(H, "###0h") + " " + Format(m, "00m") + " " + Format(S, "00s") + vbCrLf
    
    If STATUS_MNX.DISABLE_LIMIT_CHECKS Then
        strStatus = strStatus + "Command Limit Checks: Disabled" + vbCrLf
    Else
        strStatus = strStatus + "Command Limit Checks: Enabled" + vbCrLf
    End If
    
    If STATUS_MNX.DISABLE_FAULT_CHECKS Then
        strStatus = strStatus + "Fault Checks: Disabled" + vbCrLf
    Else
        strStatus = strStatus + "Fault Checks: Enabled" + vbCrLf
    End If
    
    If STATUS_MNX.SPEAKER_EN Then
        strStatus = strStatus + "Speaker: Enabled" + vbCrLf
    Else
        strStatus = strStatus + "Speaker: Disabled" + vbCrLf
    End If
    
    If STATUS_MNX.WARMUP_STEP > 127 Then    ' MSB is set if warmup is running
        strStatus = strStatus + "Warmup Step: " + Format(STATUS_MNX.WARMUP_STEP And 15, "#0") + vbCrLf
        strStatus = strStatus + "Warmup step time: " + Format(STATUS_MNX.WARMUP_TIME, "##0s") + vbCrLf
    Else
        strStatus = strStatus + "Warmup: not running" + vbCrLf
    End If
    MiniX2_StatusToString = strStatus
    Exit Function
MiniX2_StatusToStringErr:
    'exit on error
End Function

Public Function MiniX2_StatusDisplayParameterName(STATUS_MNX As Stat_MNX) As String
    Dim strStatus As String
    Dim H As Long, m As Long, S As Long
    On Error GoTo MiniX2_StatusDisplayParameterNameErr
    MiniX2_StatusDisplayParameterName = ""
    If (STATUS_MNX.SN = 0) Then Exit Function
    strStatus = ""
    '----------------------------------------------------------------
    strStatus = strStatus + "S/N: " + vbCrLf
    strStatus = strStatus + "FW: " + vbCrLf
    strStatus = strStatus + "Supply Voltage (Mini-X): " + vbCrLf
    strStatus = strStatus + "Supply Voltage (to tube): " + vbCrLf
    strStatus = strStatus + "Tube HV Mon: " + vbCrLf
    strStatus = strStatus + "Tube HV Mon (raw): " + vbCrLf
    strStatus = strStatus + "Tube Current Mon: " + vbCrLf
    strStatus = strStatus + "Tube Current Mon (raw): " + vbCrLf
    strStatus = strStatus + "Interlock Current: " + vbCrLf
    strStatus = strStatus + "Board Temp: " + vbCrLf
    '----------------------------------------------------------------
    strStatus = strStatus + "HV_EN State: " + vbCrLf
    strStatus = strStatus + "Current Fault: " + vbCrLf
    strStatus = strStatus + "Previous Fault: " + vbCrLf
    strStatus = strStatus + "Tube Runtime: " + vbCrLf
    strStatus = strStatus + "Command Limit Checks: " + vbCrLf
    strStatus = strStatus + "Fault Checks: " + vbCrLf
    strStatus = strStatus + "Speaker: " + vbCrLf
    If STATUS_MNX.WARMUP_STEP > 127 Then    ' MSB is set if warmup is running
        strStatus = strStatus + "Warmup Step: " + vbCrLf
        strStatus = strStatus + "Warmup step time: " + vbCrLf
    Else
        strStatus = strStatus + "Warmup: " + vbCrLf
    End If
    MiniX2_StatusDisplayParameterName = strStatus
    Exit Function
MiniX2_StatusDisplayParameterNameErr:
    'exit on error
End Function

Public Function MiniX2_StatusDisplayData(STATUS_MNX As Stat_MNX) As String
    Dim strStatus As String
    Dim H As Long, m As Long, S As Long
    On Error GoTo MiniX2_StatusDisplayDataErr
   MiniX2_StatusDisplayData = ""
    If (STATUS_MNX.SN = 0) Then Exit Function
    strStatus = ""
    '----------------------------------------------------------------
    strStatus = strStatus + Format(STATUS_MNX.SN, "0000") + vbCrLf
    strStatus = strStatus + Format(STATUS_MNX.FW \ 16, "#0.") + Format(STATUS_MNX.FW And 15, "00.") + Format(STATUS_MNX.Build, "00") + vbCrLf
    strStatus = strStatus + Format(STATUS_MNX.PWR_IN, "#0.00V") + vbCrLf
    strStatus = strStatus + Format(STATUS_MNX.PWR_XRAY, "#0.00V") + vbCrLf
    strStatus = strStatus + Format(STATUS_MNX.HV_MON, "#0.00kV") + vbCrLf
    strStatus = strStatus + Format(STATUS_MNX.HV_MON_RAW, "0.000V") + vbCrLf
    strStatus = strStatus + Format(STATUS_MNX.I_MON, "##0.00uA") + vbCrLf
    strStatus = strStatus + Format(STATUS_MNX.I_MON_RAW, "0.000V") + vbCrLf
    strStatus = strStatus + Format(STATUS_MNX.LAMP_I, "#0.00mA") + vbCrLf
    strStatus = strStatus + Format(STATUS_MNX.Temp, "##0°C") + vbCrLf
    '----------------------------------------------------------------
    If STATUS_MNX.HV_EN Then
        strStatus = strStatus + " Enabled" + vbCrLf
    Else
        strStatus = strStatus + " Disabled" + vbCrLf
    End If
    strStatus = strStatus + " " + Fault(STATUS_MNX.INTERLOCK_STATE) + vbCrLf
    If STATUS_MNX.LAST_FAULT > 0 Then
        strStatus = strStatus + " " + Fault(STATUS_MNX.LAST_FAULT) + vbCrLf
    Else
        strStatus = strStatus + " none" + vbCrLf
    End If
    
    H = STATUS_MNX.RUNTIME \ 3600
    m = (STATUS_MNX.RUNTIME - H * 3600) \ 60
    S = STATUS_MNX.RUNTIME - H * 3600 - m * 60
    strStatus = strStatus + " " + Format(H, "###0h") + " " + Format(m, "00m") + " " + Format(S, "00s") + vbCrLf
    
    If STATUS_MNX.DISABLE_LIMIT_CHECKS Then
        strStatus = strStatus + " Disabled" + vbCrLf
    Else
        strStatus = strStatus + " Enabled" + vbCrLf
    End If
    
    If STATUS_MNX.DISABLE_FAULT_CHECKS Then
        strStatus = strStatus + " Disabled" + vbCrLf
    Else
        strStatus = strStatus + " Enabled" + vbCrLf
    End If
    
    If STATUS_MNX.SPEAKER_EN Then
        strStatus = strStatus + " Enabled" + vbCrLf
    Else
        strStatus = strStatus + " Disabled" + vbCrLf
    End If
    
    If STATUS_MNX.WARMUP_STEP > 127 Then    ' MSB is set if warmup is running
        strStatus = strStatus + " " + Format(STATUS_MNX.WARMUP_STEP And 15, "#0") + vbCrLf
        strStatus = strStatus + " " + Format(STATUS_MNX.WARMUP_TIME, "##0s") + vbCrLf
    Else
        strStatus = strStatus + " not running" + vbCrLf
    End If
   MiniX2_StatusDisplayData = strStatus
    Exit Function
MiniX2_StatusDisplayDataErr:
    'exit on error
End Function

'===================================================================================
' Here's the tube table structure from the Mini-X embedded code
'struct MNX_TT {                     // 64-byte tube and interlock table
'    unsigned char PN[20];           // 0-19: 20-character P/N
'    unsigned char SN[12];           // 20-31: 12-character S/N
'    unsigned char HVMIN;            // 32
'    unsigned char HVMAX;            // 33
'    unsigned char IMIN;             // 34
'    unsigned int  IMAX;             // 35-36
'    unsigned char PMAX;             // 37
'    unsigned char HVMIN_alt;        // 38
'    unsigned char HVMAX_alt;        // 39
'    unsigned char IMIN_alt;         // 40
'    unsigned int  IMAX_alt;         // 41-42
'    unsigned char PMAX_alt;         // 43
'    unsigned int  HVSCALE;          // 44-45
'    unsigned int  ISCALE;           // 46-47
'    unsigned char MNX_Interlock_V;      // 48: 19.5mV/LSB
'    unsigned int  MNX_Interlock_MinI;   // 49-50: 199uA/LSB
'    unsigned int  MNX_Interlock_MaxI;   // 51-52: 199uA/LSB
'    unsigned char MISC[9];          // 53-61
'    unsigned int  CHKSUM;           // 62-63
'    };
'===================================================================================
Public Function Process_MNX_Tube_Table(PIN As Packet_In, ByRef TubeInterlockTable As TubeInterlockTableType) As String
' This is called by Form1.ParsePacket
    Dim L As Long
    Dim idxData As Long
    Dim strTubeTable As String
    Dim strTemp As String
    
    On Error GoTo Process_MNX_Tube_TableErr
    Process_MNX_Tube_Table = ""
    
    strTubeTable = ""
    strTubeTable = strTubeTable + "======= Tube Table =======" + vbCrLf
    strTemp = ""
    For idxData = 0 To 19
        If PIN.Data(idxData) > 0 Then
            strTemp = strTemp + Chr(PIN.Data(idxData))
        Else
            Exit For
        End If
    Next idxData
    TubeInterlockTable.PartNumber = strTemp
    strTubeTable = strTubeTable & "Tube Part Number: " & strTemp & vbNewLine
    
    strTemp = ""
    For idxData = 20 To 31
        If PIN.Data(idxData) > 0 Then
            strTemp = strTemp + Chr(PIN.Data(idxData))
        Else
            Exit For
        End If
    Next idxData
    TubeInterlockTable.SerialNumber = strTemp
    strTubeTable = strTubeTable & "Tube Serial Number: " & strTemp & vbNewLine

    ' 55-61: misc (unused)
    strTemp = ""
    For idxData = 62 To 93
        If PIN.Data(idxData) > 0 Then
            strTemp = strTemp + Chr(PIN.Data(idxData))
        Else
            Exit For
        End If
    Next idxData
    TubeInterlockTable.Description = strTemp
    strTubeTable = strTubeTable & "Tube Description: " & strTemp & vbNewLine

    strTemp = CStr(PIN.Data(32))                       ' 8-bit HVMin
    TubeInterlockTable.HVmin_kV = Val(strTemp)
    strTubeTable = strTubeTable & "HVmin: " & strTemp & "kV" & vbNewLine

    strTemp = CStr(PIN.Data(33))                       ' 8-bit HVMax
    TubeInterlockTable.HVmax_kV = Val(strTemp)
    strTubeTable = strTubeTable & "HVmax: " & strTemp & "kV" & vbNewLine

    strTemp = CStr(PIN.Data(34))                        ' 8-bit Imin
    TubeInterlockTable.Imin_uA = Val(strTemp)
    strTubeTable = strTubeTable & "Imin: " & strTemp & "uA" & vbNewLine

    strTemp = CStr(PIN.Data(35) * 256 + PIN.Data(36))   ' 16 bit Imax, 35 MSB, 36 LSB
    TubeInterlockTable.Imax_uA = Val(strTemp)
    strTubeTable = strTubeTable & "Imax: " & strTemp & "uA" & vbNewLine

    strTemp = Format(PIN.Data(37) / 4, "#0.00")        ' 8-bit 6.2 fixed point Pmax
    TubeInterlockTable.Pmax_Anode_W = Val(strTemp)
    strTubeTable = strTubeTable & "Pmax anode: " & strTemp & "W" & vbNewLine
    
'''    '"Alternate limits"
'''    strTemp = Str(PIN.Data(38))       ' 8-bit HVMin
'''    TubeInterlockTable.HVmin_kV_Alt = Val(strTemp)
'''    strTubeTable = strTubeTable & "HVmin (kV) Alt: " & strTemp & vbNewLine
'''
'''    strTemp = Str(PIN.Data(39))       ' 8-bit HVMax
'''    TubeInterlockTable.HVmax_kV_Alt = Val(strTemp)
'''    strTubeTable = strTubeTable & "HVmax (kV) Alt"
'''
'''    strTemp = Str(PIN.Data(40))        ' 8-bit Imin
'''    TubeInterlockTable.Imin_uA_Alt = Val(strTemp)
'''    strTubeTable = strTubeTable & "Imin (uA) Alt: " & strTemp & vbNewLine
'''
'''    strTemp = Str(PIN.Data(41) * 256 + PIN.Data(42))   ' 16 bit Imax, 41 MSB, 42 LSB
'''    TubeInterlockTable.Imax_uA_Alt = Val(strTemp)
'''    strTubeTable = strTubeTable & "Imax (uA) Alt: " & strTemp & vbNewLine
'''
'''    strTemp = Format(PIN.Data(43) / 4, "#0.00")        ' 8-bit 6.2 fixed point Pmax
'''    TubeInterlockTable.Pmax_Anode_W_Alt = Val(strTemp)
'''    strTubeTable = strTubeTable & "Pmax anode (W) Alt: " & strTemp & vbNewLine
    
    strTemp = Format((PIN.Data(44) * 256 + PIN.Data(45)) / 256, "##0.000")  ' 16 bit 8.8 fixed point, 44 MSB, 45 LSB
    TubeInterlockTable.HVscale_kVperV = Val(strTemp)
    strTubeTable = strTubeTable & "HVscale: " & strTemp & "kV/V" & vbNewLine
    
    strTemp = Format((PIN.Data(46) * 256 + PIN.Data(47)) / 256, "##0.000")   ' 16 bit 8.8 fixed point, 46 MSB, 47 LSB
    TubeInterlockTable.Iscale_uAperV = Val(strTemp)
    strTubeTable = strTubeTable & "Iscale: " & strTemp & "uA/V" & vbNewLine
    
    strTubeTable = strTubeTable + "======= Interlock Table ===========" + vbCrLf
   
    strTemp = Format(CSng(PIN.Data(48)) * 0.02, "0.000")     ' 20.0mV/LSB, 8 bit
    TubeInterlockTable.Interlock_Voltage_V = Val(strTemp)
    strTubeTable = strTubeTable & "Interlock Voltage: " & strTemp & "V" & vbNewLine
    
    strTemp = Format(CSng(PIN.Data(49) * 256 + PIN.Data(50)) * 0.01244, "#0.00")  ' 12.44uA/LSB, 12 bit, 49 MSB, 50 LSB
    TubeInterlockTable.Interlock_min_I_mA = Val(strTemp)
    strTubeTable = strTubeTable & "Interlock min I: " & strTemp & "mA" & vbNewLine
    
    strTemp = Format(CSng(PIN.Data(51) * 256 + PIN.Data(52)) * 0.01244, "#0.00")  ' 12.44uA/LSB, 12 bit, 51 MSB, 52 LSB
    TubeInterlockTable.Interlock_max_I_mA = Val(strTemp)
    strTubeTable = strTubeTable & "Interlock max I: " & strTemp & "mA" & vbNewLine

    strTemp = Format(CSng(PIN.Data(53)) / 16, "#0.00")   ' 8-bit 4.4 fixed point Tube supply min
    TubeInterlockTable.Tube_Supply_Min_V = Val(strTemp)
    strTubeTable = strTubeTable & "Tube Supply Min: " & strTemp & "V" & vbNewLine
    
    strTemp = Format(CSng(PIN.Data(54)) / 16, "#0.00")   ' 8-bit 4.4 fixed point Tube supply max
    TubeInterlockTable.Tube_Supply_Max_V = Val(strTemp)
    strTubeTable = strTubeTable & "Tube Supply Max: " & strTemp & "V" & vbNewLine


    Process_MNX_Tube_Table = strTubeTable
    Exit Function
    
    
Process_MNX_Tube_TableErr:

End Function


Public Function Process_MNX_Timestamp(PIN As Packet_In) As String
    Dim LastOnTime As Date
    Dim Timestamp_flags As Byte
    Dim Timetag_lag As Long

    On Error GoTo Process_MNX_TimestampErr
    
    Process_MNX_Timestamp = Format(CStr(Now), "MM/DD/YYYY HH:NN:SS AMPM")

    Timestamp_flags = PIN.Data(0)
    If Timestamp_flags < 128 Then
        LastOnTime = DateSerial(2000 + PIN.Data(3), PIN.Data(1), PIN.Data(2))   ' date
        LastOnTime = LastOnTime + TimeSerial(PIN.Data(4), PIN.Data(5), PIN.Data(6))
        Timetag_lag = CLng(PIN.Data(7) And &H7F) * (2 ^ 24) + CLng(PIN.Data(8)) * (2 ^ 16) + CLng(PIN.Data(9)) * 256 + CLng(PIN.Data(10))
        LastOnTime = DateAdd("s", Timetag_lag, LastOnTime)
        Process_MNX_Timestamp = Format(CStr(LastOnTime), "MM/DD/YYYY HH:NN:SS AMPM")
        ' Get runtime from status instead
        'Runtime = CLng(PIN.DATA(11) And &H7F) * (2 ^ 24) + CLng(PIN.DATA(12)) * (2 ^ 16) + CLng(PIN.DATA(13)) * 256 + CLng(PIN.DATA(14))
'''    Else    ' unintialized timestamp
    End If
    
    
    Exit Function

Process_MNX_TimestampErr:
    'MsgBox Err.Description
End Function




